﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using XL_KVMC;

namespace XL_KVMC.Protocols
{
    public class KVMC_Protocol : IProtocol
    {
        private McFrame FrameType;  // 框架类型
        private uint SerialNumber;  // 序列号
        private uint NetwrokNumber; // 网络号
        private uint PcNumber;     // 电脑号码
        private uint IoNumber;      // 请求的单元 I/O 编号
        private uint ChannelNumber { get; set; } // 请求目标单元站号
        private uint CpuTimer;      //CPU监控定时器
        private int ResultCode;     // 退出代码
        public KVMC_Protocol(McFrame iFrame)
        {
            FrameType = iFrame;
            SerialNumber = 0x0001u;
            NetwrokNumber = 0x0000u;
            PcNumber = 0x00FFu;
            IoNumber = 0x03FFu;
            ChannelNumber = 0x0000u;
            CpuTimer = 0x0010u;
        }

        public byte[] Deserialize(IList<byte> data)
        {
            int min = (FrameType == McFrame.MC3E) ? 11 : 15;
            byte[] bytes = default;
            if (min <= data.Count)
            {
                var btCount = new[] { data[min - 4], data[min - 3] };
                var btCode = new[] { data[min - 2], data[min - 1] };
                int rsCount = BitConverter.ToUInt16(btCount, 0);
                ResultCode = BitConverter.ToUInt16(btCode, 0);
                bytes = new byte[rsCount - 2];
                Buffer.BlockCopy(data.ToArray(), min, bytes, 0, bytes.Length);
            }
            return bytes;
        }

        public byte[] Serialize(IList<byte> data)
        {
            var dataLength = (uint)(data.Count + 2);
            var ret = new List<byte>(data.Count + 16);
            uint frame = (FrameType == McFrame.MC3E) ? 0x0050u :
                         (FrameType == McFrame.MC4E) ? 0x0054u : 0x0000u;
            ret.Add((byte)frame);
            ret.Add((byte)(frame >> 8));
            if (FrameType == McFrame.MC4E)
            {
                ret.Add((byte)SerialNumber);
                ret.Add((byte)(SerialNumber >> 8));
                ret.Add(0x00);
                ret.Add(0x00);
            }
            ret.Add((byte)NetwrokNumber);
            ret.Add((byte)PcNumber);
            ret.Add((byte)IoNumber);
            ret.Add((byte)(IoNumber >> 8));
            ret.Add((byte)ChannelNumber);
            ret.Add((byte)dataLength);
            ret.Add((byte)(dataLength >> 8));
            ret.Add((byte)CpuTimer);
            ret.Add((byte)(CpuTimer >> 8));
            ret.AddRange(data);
            return ret.ToArray();
        }

        public bool Verify(IList<byte> bytes)
        {
            var min = (FrameType == McFrame.MC3E) ? 11 : 15;
            var btCount = new[] { bytes[min - 4], bytes[min - 3] };
            var btCode = new[] { bytes[min - 2], bytes[min - 1] };
            var rsCount = BitConverter.ToUInt16(btCount, 0) - 2;
            var rsCode = BitConverter.ToUInt16(btCode, 0);
            return (rsCode == 0 && rsCount == (bytes.Count - min));
        }
    }
}
